#include "XgW32Process.h"
#include <tchar.h>
#include <psapi.h>


XgW32Process::XgW32Process()
{
	_hProcess = NULL;
}

XgW32Process::XgW32Process(DWORD pid)
: _pid(pid)
{
	_hProcess = NULL;
}

XgW32Process::XgW32Process(const XgW32Process& proc)
{
	_hProcess = NULL;
	_pid = proc._pid;
}

XgW32Process::~XgW32Process(void)
{
	closeHandle();
}

bool XgW32Process::openProcess()
{
	if(_hProcess)
	{
		OutputDebugString( _T("XgW32Process::openProcess : Handle already opened\n") );
		return true;
	}

	_hProcess = OpenProcess( PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, _pid );

	return ( _hProcess != NULL );
}

bool XgW32Process::closeHandle()
{
	if(!_hProcess)
	{
		OutputDebugString( _T("XgW32Process::closeProcess : Handle already closed\n") );
		return true;
	}

	CloseHandle(_hProcess);
	_hProcess = NULL;
	return true;
}

TSTRING XgW32Process::name()
{
	// Get a handle to the process.
	openProcess();

	TCHAR szProcessName[MAX_PATH] = _T("<unknown>");

	TSTRING sProcessName = szProcessName;

	// Get the process name.
	if (NULL != _hProcess )
	{
		HMODULE hMod;
		DWORD cbNeeded;

		if ( EnumProcessModules( _hProcess, &hMod, sizeof(hMod), &cbNeeded) )
		{
			GetModuleBaseName( _hProcess, hMod, szProcessName, sizeof(szProcessName)/sizeof(TCHAR) );
		}

		sProcessName = szProcessName;
	}
	else
	{
		OutputDebugString( _T("XgW32Process::name : Process handle is closed\n") );
	}

	return sProcessName;
}

DWORD XgW32Process::pid()
{
	return _pid;
}

TSTRING XgW32Process::getModuleName(HMODULE hModule)
{
	TCHAR szName[MAX_PATH];
	openProcess();
	if( GetModuleBaseName( _hProcess, hModule, szName, MAX_PATH ) )
	{
		return szName;
	}
	else
	{
		return _T("<unknown>");
	}
}

TSTRING XgW32Process::getModulePath(HMODULE hModule)
{
	TCHAR szPath[MAX_PATH];
	openProcess();
	if( GetModuleFileNameEx( _hProcess, hModule, szPath, MAX_PATH ) )
	{
		return szPath;
	}
	else
	{
		return _T("<unknown>");
	}
}

bool XgW32Process::inject()
{
	HANDLE hProcess = OpenProcess( PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, FALSE,_pid );
	if(hProcess == NULL)
	{
		return false;
	}

	HMODULE hMod = LoadLibrary( _T("kernel32.dll") );
	if(hMod == NULL)
	{
		CloseHandle(hProcess);
		return false;
	}

	FARPROC hLoadLibraryA = GetProcAddress(hMod, "LoadLibraryA");
	if(hLoadLibraryA == NULL)
	{
		CloseHandle(hProcess);
		FreeLibrary(hMod);
		return false;
	}

	char dllname[64] = "c:\\XgRemoteCode.dll";
	SIZE_T cBytes;

	LPVOID lpRemote = VirtualAllocEx(hProcess, 0, 64, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
	LONG res = WriteProcessMemory(hProcess, lpRemote, (LPCVOID)dllname, 64, &cBytes);

	HANDLE rThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)hLoadLibraryA, lpRemote, 0, NULL);
	WaitForSingleObject(rThread, INFINITE); 

	VirtualFreeEx(hProcess, lpRemote, 0, MEM_RELEASE);

	CloseHandle(hProcess);
	FreeLibrary(hMod);

	return true;
}

XgW32ProcessModules XgW32Process::getModules()
{
	return XgW32ProcessModules(_pid);
}

DWORD XgW32Process::enumModules(HMODULE* aModules, DWORD size)
{
	openProcess();
	DWORD cBytes;

	if( !EnumProcessModules(_hProcess, aModules, size, &cBytes) )
	{
		return 0;
	}

	DWORD cModules = cBytes / sizeof(HMODULE);
	return cModules;
}